
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/mod_devicetable.h>
#include <linux/log2.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <asm/uaccess.h>


#define  I2C_W_DATA  100
#define	 I2C_R_DATA  101

static int major;
static struct class *at24c20_class;


static struct i2c_client  *at24c20_client;



static int at24c20_open(struct inode *node, struct file *file)
{
	printk("%s %s  line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}


static int at24c20_close(struct inode *node, struct file *file)
{
	printk("%s %s  line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}


/* 
*   user_buffer[0]: 数据存储地址（8位)；
*   user_buffer[1]: 数据；	
*/
static long at24c20_ioctl (struct file *file, unsigned int cmd, unsigned long arg)
{

	unsigned int kernel_buffer[2];
	struct i2c_msg at24c20_msg[2];
	unsigned char data_address;
	unsigned char write_byte_buffer[2];
	unsigned int *user_buffer = (unsigned int *)arg;
	
	copy_from_user(kernel_buffer, user_buffer, 8);
	data_address = kernel_buffer[0];
	
	switch(cmd)
	{
		case I2C_W_DATA:
		{
			write_byte_buffer[0] = kernel_buffer[0];
			write_byte_buffer[1] = kernel_buffer[1];
			at24c20_msg[0].addr = at24c20_client->addr;
			at24c20_msg[0].flags =  0; /*写*/
			at24c20_msg[0].len = 2;  
			at24c20_msg[0].buf = write_byte_buffer;
			i2c_transfer(at24c20_client->adapter, at24c20_msg, 1);
			mdelay(20);
			break;
		}

		case I2C_R_DATA:
		{
			at24c20_msg[0].addr = at24c20_client->addr;
			at24c20_msg[0].flags =  0;  /*写*/
			at24c20_msg[0].len = 1;     /*1字节(数据存储地址）*/
			at24c20_msg[0].buf = &data_address;
			
			at24c20_msg[1].addr = at24c20_client->addr;
			at24c20_msg[1].flags = I2C_M_RD;   /*读*/
			at24c20_msg[1].len = 1;    /*1字节(数据）*/
			at24c20_msg[1].buf = (unsigned char *)&kernel_buffer[1];
			i2c_transfer(at24c20_client->adapter, at24c20_msg, 2);
			copy_to_user(user_buffer, kernel_buffer, 8);
			break;
		}
				
	}
	return 0;
	 
}


static struct file_operations at24c20_ops = {
	.owner  = THIS_MODULE,
	.open    = at24c20_open,
	.release = at24c20_close,
	.unlocked_ioctl = at24c20_ioctl,
};


static struct of_device_id of_at24c20_match_table[] = {
	{ .compatible = "at24c02,zmq", },
	{ },
};

static struct i2c_device_id at24c20_table[] = {
	{"at24c20,zmq",},
	{},
};

static int at24c20_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	
	printk("%s %s  line %d\n", __FILE__, __FUNCTION__, __LINE__);
	
	at24c20_client = client;

	major = register_chrdev(0, "zmq_at24c20_chrdev", &at24c20_ops);
	at24c20_class = class_create(THIS_MODULE, "at24c02_class_name");
	if(IS_ERR(at24c20_class))
	{
		unregister_chrdev(major, "zmq_at24c20_chrdev");
		return PTR_ERR(at24c20_class);
	}
	device_create(at24c20_class, NULL, MKDEV(major, 0), NULL, "at24c20_zmq");
	return 0;
	
}

static int at24c20_remove(struct i2c_client *client)
{

	device_destroy(at24c20_class, MKDEV(major, 0));
	class_destroy(at24c20_class);
	unregister_chrdev(major, "zmq_at24c20_chrdev");
	return 0;
}


static struct i2c_driver at24c20_drv = {
	.probe = at24c20_probe,
	.remove = at24c20_remove,
	.driver = 	{
		.name = "at24c20",
		.of_match_table = of_at24c20_match_table,
	},

	.id_table = at24c20_table,
};



static int at24c20_init(void)
{
	printk("%s %s  line %d\n", __FILE__, __FUNCTION__, __LINE__);
	i2c_add_driver(&at24c20_drv);
	
	return 0;
}


static void at24c20_exit(void)
{
	printk("%s %s  line %d\n", __FILE__, __FUNCTION__, __LINE__);

	i2c_del_driver(&at24c20_drv);
}


module_init(at24c20_init);
module_exit(at24c20_exit);
MODULE_LICENSE("GPL");






